package com.mulong.common.util;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import lombok.extern.slf4j.Slf4j;

/**
 * MulongUtil
 * 
 * @author mulong
 * @data 2021-06-13 23:43:29
 */
@Slf4j
public class MulongUtil {
    private static DecimalFormat DECIMAL_FORMAT_FOR_LONG = new DecimalFormat("###,###");
    private static DecimalFormat DECIMAL_FORMAT_FOR_INT = new DecimalFormat("###,###");
    private static DecimalFormat DECIMAL_FORMAT_FOR_VOLUME = new DecimalFormat("###,##0.##");
    private static DecimalFormat DECIMAL_FORMAT_FOR_MONEY = new DecimalFormat("###,##0.00");
    private static DecimalFormat DECIMAL_FORMAT_FOR_NAV = new DecimalFormat("###,##0.0000");
    private static DecimalFormat DECIMAL_FORMAT_FOR_RATE = new DecimalFormat("###,##0.00%");

    private static String desKey;

    private MulongUtil() {
        throw new IllegalStateException("Utility class");
    }

    public static void setDesKey(String key) {
        desKey = key;
    }

    public static String desEncrypt(String content) {
        DES des = SecureUtil.des(desKey.getBytes());
        return des.encryptHex(content);
    }

    public static String desDecrypt(String data) {
        DES des = SecureUtil.des(desKey.getBytes());
        return des.decryptStr(data);
    }

    public static boolean isEqual(double d1, double d2) {
        return isEqual(d1, d2, 0.000001);
    }

    public static boolean isEqual(double d1, double d2, double limit) {
        return Math.abs(d1 - d2) < limit;
    }

    public static boolean isGreaterThan(double d1, double d2) {
        if (isEqual(d1, d2)) {
            return false;
        }
        return d1 > d2;
    }

    public static double parseToDouble(String s) {
        s = s.replaceAll(",", StringUtils.EMPTY);
        return Double.parseDouble(s);
    }

    public static double parseToInt(String s) {
        s = s.replaceAll(",", StringUtils.EMPTY);
        return Integer.parseInt(s);
    }

    public static String formatLong(long num) {
        return DECIMAL_FORMAT_FOR_LONG.format(num);
    }

    public static String formatInt(int num) {
        return DECIMAL_FORMAT_FOR_INT.format(num);
    }

    public static String formatVolume(double volume) {
        return DECIMAL_FORMAT_FOR_VOLUME.format(volume);
    }

    public static String formatVolume(BigDecimal volume) {
        return DECIMAL_FORMAT_FOR_VOLUME.format(volume);
    }

    public static String formatMoney(double money) {
        return DECIMAL_FORMAT_FOR_MONEY.format(money);
    }

    public static String formatMoney(BigDecimal money) {
        return DECIMAL_FORMAT_FOR_MONEY.format(money);
    }

    public static String formatMoneyWithPrefix(double money) {
        if (isEqual(money, 0)) {
            return "0.00";
        }
        if (isGreaterThan(money, 0)) {
            return "+" + formatMoney(money);
        } else {
            return formatMoney(money);
        }
    }

    public static String formatMoneyWithPrefix(BigDecimal money) {
        return formatMoneyWithPrefix(money.doubleValue());
    }

    public static String formatNav(double nav) {
        return DECIMAL_FORMAT_FOR_NAV.format(nav);
    }

    public static String formatNav(BigDecimal nav) {
        return DECIMAL_FORMAT_FOR_NAV.format(nav);
    }

    public static String formatRate(double rate) {
        return DECIMAL_FORMAT_FOR_RATE.format(rate);
    }

    public static String formatRate(BigDecimal rate) {
        return formatRate(rate.doubleValue());
    }

    public static String formatRateWithPrefix(double rate) {
        if (isEqual(rate, 0)) {
            return "0.00%";
        }
        if (isGreaterThan(rate, 0)) {
            return "+" + formatRate(rate);
        } else {
            return formatRate(rate);
        }
    }

    public static String formatRateWithPrefix(BigDecimal rate) {
        return formatRateWithPrefix(rate.doubleValue());
    }

    public static final ResponseEntity<byte[]> buildDownloadResponse(String filename, String srcFile) {
        byte[] content = null;
        try (InputStream is = new FileInputStream(srcFile);
                ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            int len = 0;
            byte[] buffer = new byte[4096];
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            os.flush();
            content = os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return buildDownloadResponse(filename, content);
    }

    public static final ResponseEntity<byte[]> buildDownloadResponse(String filename, byte[] content) {
        return buildDownloadResponse("application/octet-stream", filename, content);
    }

    public static final ResponseEntity<byte[]> buildDownloadResponse(String contentType, String filename, byte[] content) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", contentType);
        try {
            headers.add("Content-Disposition", "attchement;filename*=UTF-8''" + URLEncoder.encode(filename, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return new ResponseEntity<>(content, headers, HttpStatus.OK);
    }

    /**
     * 生成uuid
     */
    public static String generateUuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * workbook对象转换为字节数组
     */
    public static byte[] toByteArray(HSSFWorkbook workbook) {
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            workbook.write(os);
            os.flush();
            return os.toByteArray();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 添加标题
     */
    public static void addTitle(HSSFWorkbook workbook, HSSFSheet sheet, String[] values) {
        addTitle(sheet, getDefaultTitleStyle(workbook, (short)13), values);
    }

    /**
     * 添加标题
     */
    public static void addTitle(HSSFWorkbook workbook, HSSFSheet sheet, List<String> values) {
        addTitle(sheet, getDefaultTitleStyle(workbook, (short)13), values);
    }

    /**
     * 添加标题
     */
    public static void addTitle(HSSFSheet sheet, HSSFCellStyle styleField, String[] values) {
        HSSFRow rowField = sheet.createRow(sheet.getLastRowNum()+1);
        for (int j = 0; j < values.length; j++) {
            HSSFCell cell = rowField.createCell(j);
            cell.setCellValue(values[j]);
            cell.setCellStyle(styleField);
        }
    }

    /**
     * 添加标题
     */
    public static void addTitle(HSSFSheet sheet, HSSFCellStyle styleField, List<String> values) {
        HSSFRow rowField = sheet.createRow(sheet.getLastRowNum()+1);
        for (int j = 0; j < values.size(); j++) {
            HSSFCell cell = rowField.createCell(j);
            cell.setCellValue(values.get(j));
            cell.setCellStyle(styleField);
        }
    }

    /**
     * 获取默认标题单元格样式
     */
    private static HSSFCellStyle getDefaultTitleStyle(HSSFWorkbook workbook, short fontSize) {
        HSSFCellStyle style = getDefaultCellStyle(workbook);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setFillForegroundColor(HSSFColor.HSSFColorPredefined.YELLOW.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints(fontSize);
        font.setBold(true);
        style.setFont(font);
        return style;
    }

    /**
     * 默认单元格样式
     */
    public static HSSFCellStyle getNumber2Style(HSSFWorkbook workbook) {
        HSSFCellStyle numberStyle = getDefaultCellStyle(workbook);
        numberStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
        return numberStyle;
    }

    /**
     * 默认单元格样式
     */
    public static HSSFCellStyle getNumber4Style(HSSFWorkbook workbook) {
        HSSFCellStyle numberStyle = getDefaultCellStyle(workbook);
        numberStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,####0.0000"));
        return numberStyle;
    }

    /**
     * 默认单元格样式
     */
    public static HSSFCellStyle getDefaultCellStyle(HSSFWorkbook workbook) {
        HSSFCellStyle styleData = workbook.createCellStyle();
        styleData.setAlignment(HorizontalAlignment.CENTER);
        styleData.setVerticalAlignment(VerticalAlignment.CENTER);
        return styleData;
    }

    public static String getStringCellValue(Cell cell) {
        String cellValue = StringUtils.EMPTY;
        // 以下是判断数据的类型
        switch (cell.getCellType()) {
            case NUMERIC:
                // 数字
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    cellValue = sdf.format(org.apache.poi.ss.usermodel.DateUtil.getJavaDate(cell.getNumericCellValue()));
                } else {
                    DataFormatter dataFormatter = new DataFormatter();
                    cellValue = dataFormatter.formatCellValue(cell);
                }
                break;
            case STRING:
                // 字符串
                cellValue = cell.getStringCellValue();
                break;
            case BOOLEAN:
                // Boolean
                cellValue = cell.getBooleanCellValue() + StringUtils.EMPTY;
                break;
            case FORMULA:
                // 公式
                cellValue = cell.getCellFormula() + StringUtils.EMPTY;
                break;
            case BLANK:
                // 空值
                cellValue = StringUtils.EMPTY;
                break;
            case ERROR:
                // 故障
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

}
